from __future__ import annotations
from typing import Iterator
from abc import abstractmethod

from composite.menu import menu


class MenuComponent(menu.MenuComponent):
    @abstractmethod
    def __iter__(self):
        ...


class Menu(MenuComponent, menu.Menu):
    def __iter__(self):
        return CompositeIterator(iter(self.menu_components))


class MenuItem(MenuComponent, menu.MenuItem):
    def __iter__(self):
        return NullIterator()


class CompositeIterator:
    def __init__(self, iterator: Iterator[MenuComponent]):
        self._stack = [iterator]

    def __iter__(self):
        return self

    def __next__(self):
        if not self._stack:
            raise StopIteration()
        try:
            component = next(self._stack[-1])
            if isinstance(component, Menu):
                self._stack.append(iter(component.menu_components))
            return component
        except StopIteration:
            self._stack.pop()
            return next(self)


class NullIterator:
    def __iter__(self):
        return self

    def __next__(self):
        raise StopIteration


class Waitress:
    def __init__(self, all_menus: MenuComponent):
        self._all_menus = all_menus

    def print_menu(self):
        self._all_menus.print()

    def print_vegetarian_menu(self):
        iterator = iter(self._all_menus)
        print("\nVEGETARIAN MENU\n----")
        while 1:
            try:
                menu_component: MenuComponent = next(iterator)
                try:
                    if menu_component.is_vegetarian:
                        menu_component.print()
                except NotImplementedError:
                    pass
            except StopIteration:
                break


if __name__ == '__main__':
    pancake_house_menu = Menu("PANCAKE HOUSE MENU", "Breakfast")
    diner_menu = Menu("DINER MENU", "Lunch")
    cafe_menu = Menu("CAFE MENU", "Dinner")
    dessert_menu = Menu("DESSERT MENU", "Dessert of course!")
    coffee_menu = Menu("COFFEE MENU", "Stuff to go with your afternoon coffee")

    all_menus = Menu("ALL MENUS", "All menus combined")

    all_menus.add(pancake_house_menu)
    all_menus.add(diner_menu)
    all_menus.add(cafe_menu)

    pancake_house_menu.add(MenuItem(
        "K&B's Pancake Breakfast",
        "Pancakes with scrambled eggs and toast",
        True,
        2.99
    ))
    pancake_house_menu.add(MenuItem(
        "Regular Pancake Breakfast",
        "Pancakes with fried eggs, sausage",
        False,
        2.99
    ))
    pancake_house_menu.add(MenuItem(
        "Blueberry Pancakes",
        "Pancakes made with fresh blueberries, and blueberry syrup",
        True,
        3.49
    ))
    pancake_house_menu.add(MenuItem(
        "Waffles",
        "Waffles with your choice of blueberries or strawberries",
        True,
        3.59
    ))
    diner_menu.add(MenuItem(
        "Vegetarian BLT",
        "(Fakin') Bacon with lettuce & tomato on whole wheat",
        True,
        2.99
    ))
    diner_menu.add(MenuItem(
        "BLT",
        "Bacon with lettuce & tomato on whole wheat",
        False,
        2.99
    ))
    diner_menu.add(MenuItem(
        "Soup of the day",
        "A bowl of the soup of the day, with a side of potato salad",
        False,
        3.29
    ))
    diner_menu.add(MenuItem(
        "Hot Dog",
        "A hot dog, with saurkraut, relish, onions, topped with cheese",
        False,
        3.05
    ))
    diner_menu.add(MenuItem(
        "Steamed Veggies and Brown Rice",
        "Steamed vegetables over brown rice",
        True,
        3.99
    ))
    diner_menu.add(MenuItem(
        "Pasta",
        "Spaghetti with marinara sauce, and a slice of sourdough bread",
        True,
        3.89
    ))

    diner_menu.add(dessert_menu)

    dessert_menu.add(MenuItem(
        "Apple Pie",
        "Apple pie with a flakey crust, topped with vanilla icecream",
        True,
        1.59
    ))
    dessert_menu.add(MenuItem(
        "Cheesecake",
        "Creamy New York cheesecake, with a chocolate graham crust",
        True,
        1.99
    ))
    dessert_menu.add(MenuItem(
        "Sorbet",
        "A scoop of raspberry and a scoop of lime",
        True,
        1.89
    ))
    dessert_menu.add(MenuItem(
        "Veggie Burger and Air Fries",
        "Veggie burger on a whole wheat bun, lettuce, tomato, and fries",
        True,
        3.99
    ))
    dessert_menu.add(MenuItem(
        "Soup of the day",
        "A cup of the soup of the day, with a side salad",
        False,
        3.69
    ))
    dessert_menu.add(MenuItem(
        "Burrito",
        "A large burrito, with whole pinto beans, salsa, guacamole",
        True,
        4.29
    ))

    cafe_menu.add(coffee_menu)

    coffee_menu.add(MenuItem(
        "Coffee Cake",
        "Crumbly cake topped with cinnamon and walnuts",
        True,
        1.59
    ))
    coffee_menu.add(MenuItem(
        "Bagel",
        "Flavors include sesame, poppyseed, cinnamon raisin, pumpkin",
        False,
        0.69
    ))
    coffee_menu.add(MenuItem(
        "Biscotti",
        "Three almond or hazelnut biscotti cookies",
        True,
        0.89
    ))

    waitress = Waitress(all_menus)

    waitress.print_vegetarian_menu()